package edu.the.last.graphic;

import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.geom.Line2D;
import java.awt.geom.Line2D.Double;
import java.util.Date;
import java.util.Vector;

import javax.swing.JPanel;

import edu.the.last.Messages;
import edu.the.last.modell.Music;

/**
 * the class responsable for the wave form...
 * 
 * @author albertcsani
 * 
 */
public class SamplingGraph extends JPanel implements Runnable {
	private static final long serialVersionUID = -15635L;
	private String[] musicSounds = { Messages.getString("SamplingGraph.0"), Messages.getString("SamplingGraph.1"), Messages.getString("SamplingGraph.2"), Messages.getString("SamplingGraph.3"), Messages.getString("SamplingGraph.4"), Messages.getString("SamplingGraph.5"), Messages.getString("SamplingGraph.6"), Messages.getString("SamplingGraph.7"), Messages.getString("SamplingGraph.8"), Messages.getString("SamplingGraph.9"), Messages.getString("SamplingGraph.10"), Messages.getString("SamplingGraph.11") }; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ //$NON-NLS-6$ //$NON-NLS-7$ //$NON-NLS-8$ //$NON-NLS-9$ //$NON-NLS-10$ //$NON-NLS-11$ //$NON-NLS-12$
	private Thread thread;
	private Font font12 = new Font(Messages.getString("SamplingGraph.FontFam"), Font.PLAIN, 12); //$NON-NLS-1$
	private Font font18 = new Font(Messages.getString("SamplingGraph.FontFam"), Font.BOLD, 18); //$NON-NLS-1$
	private double duration;
	private double seconds;
	private Vector<Double> lines = new Vector<Double>();
	private double frames;
	private double barDist = 0;
	private int framesPerPixel = 500;
	private Music music;

	/**
	 * constructor
	 * 
	 * @param audioInputStream
	 *            the audioImputStream which contains the audio to "draw"
	 * @throws Exception
	 */
	public SamplingGraph(Music music) throws Exception {
		setBackground(Color.black);
		this.music = music;
		initSamplingGraph();
	}

	/**
	 * initializes the class
	 * 
	 * @param audioInputStream
	 *            the audioImputStream which contains the audio to "draw"
	 * @throws Exception
	 */
	public void initSamplingGraph() throws Exception {
		if (music.getAudioBytes() != null) {
			frames = music.getAudioBytes().length;
			createWaveForm(music.getAudioBytes());
		} else {
			frames = 0;
		}
	}

	/**
	 * creates a list containing the lines that represent the audio signals
	 * amplitude
	 * 
	 * @param audioBytes
	 *            the samples of the audio signal
	 * @throws Exception
	 */
	private void createWaveForm(byte[] audioBytes) throws Exception {
		lines.removeAllElements(); // clear the old vector
		Dimension d = getSize();
		int h = d.height - 15;
		double yLast = 0;
		for (double x = 0; x < audioBytes.length / framesPerPixel; x++) {
			int ind = (int) (framesPerPixel * x);
			double yNew = (double) (h * (128 - audioBytes[ind]) / 256);
			lines.add(new Line2D.Double(x, yLast, x, yNew));
			yLast = yNew;
		}
		repaint();
	}

	/**
	 * paints the wave form, the chords, the notes, the bars, and the cursor
	 * while playing
	 */
	public void paint(Graphics g) {
		barDist = (music.getBpb() *music.getInterval() * 2);
		Dimension d = getSize();
		int w = d.width;
		int h = d.height;
		// if (frames / framesPerPixel > 1000) {
		// h -= 20;
		// }
		if (frames != 0) {
			setPreferredSize(new Dimension((int) (frames / framesPerPixel), h));
			revalidate();
		}
		d = getSize();
		w = d.width;
		h = d.height;
		int INFOPAD = 15;
		int INFOPAD2 = 22;

		Graphics2D g2 = (Graphics2D) g;
		g2.setBackground(getBackground());
		g2.clearRect(0, 0, w, h);
		g2.setColor(Color.white);
		g2.fillRect(0, h - INFOPAD, w, INFOPAD);
		g2.fillRect(0, 0, w, INFOPAD2);

		g2.setColor(Color.black);
		g2.setFont(font12);
		// painting the notes, chores and bars
		if (music.getNotes() != null) { // painting the sounds
			duration = music.getAudioBytes().length * 1000.0 / music.getFormat().getFrameRate();
			duration = duration / 1000.0;
			for (int i = 0; i < music.getNotes().length; i++) {
				double loc = i * music.getInterval() / duration * (frames / framesPerPixel);
				if (music.getNotes()[i] != -1) {
					g2.drawString(musicSounds[music.getNotes()[i]], (int) loc + 2, h - 4);
				}
				else{
					g2.drawString(Messages.getString("SamplingGraph.Blank"), (int) loc + 2, h - 4); //$NON-NLS-1$
				}
			}
		}
		if (music.getAudioBytes() != null) { // painting the bars
			duration = music.getAudioBytes().length * 1000.0/ music.getFormat().getFrameRate();
			duration = duration / 1000.0;
			for (int i = 0; i * barDist < duration; i++) {
				double loc = i * barDist / duration * (frames / framesPerPixel);
				g2.setColor(Color.blue);
				g2.setStroke(new BasicStroke(1));
				g2.draw(new Line2D.Double(loc, 0, loc, h - 2));
			}
			if (music.getChords() != null) { // painting the chords
				g2.setFont(font18);
				duration = music.getAudioBytes().length * 1000.0 / music.getFormat().getFrameRate();
				duration = duration / 1000.0;
				for (int i = 0; i * barDist < duration; i++) {
					double loc = i * barDist / duration * (frames / framesPerPixel);
					g2.drawString(music.getChords()[i], (int) loc + 2, INFOPAD2 - 4);
				}
			}
		}

		if (frames != 0) {
			// draw the wave form
			g2.setColor(Color.green);
			for (int i = 1; i < lines.size(); i++) {
				g2.draw((Line2D) lines.get(i));
			}
			// draw cursor at current position
			if (seconds != 0) {
				double loc = seconds / duration * (frames / framesPerPixel);
				g2.setColor(Color.red);
				g2.setStroke(new BasicStroke(3));
				g2.draw(new Line2D.Double(loc, 0, loc, h - 2));
				// move to current position (scroll the wave form)
				Rectangle rect = getBounds();
				rect.x = (int) (-loc + 30);
				setBounds(rect);
			}
		}
	}

	/**
	 * starts the cursor animation
	 */
	public void start() {
		thread = new Thread(this);
		thread.setName(Messages.getString("SamplingGraph.Title")); //$NON-NLS-1$
		thread.start();
		seconds = 0;
	}

	/**
	 * stops the cursor animation
	 */
	public void stop() {
		if (thread != null) {
			thread.interrupt();
		}
		thread = null;
	}

	/**
	 * cursor animation
	 */
	public void run() {
		seconds = 0;
		long startMsec = new Date().getTime();
		long curMsec = startMsec;
		seconds = curMsec - startMsec;
		duration = 0;
		double numerator = music.getAudioBytes().length;
		numerator  = numerator *1000;
		double denominator =  music.getFormat().getFrameRate();
		duration = numerator / denominator;
		duration = duration / 1000.0;
		while (thread != null && seconds < duration) {
			curMsec = new Date().getTime();
			seconds = curMsec - startMsec;
			seconds = seconds / 1000.0;
			try {
				Thread.sleep(10);
			} catch (Exception e) {
				break;
			}
			repaint();
		}
		seconds = 0;
		repaint();
	}
}